﻿using Sunny.UI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Linq.Expressions;
using System.IO.Ports;
using System.IO;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Rebar;

namespace socketClient
{
    public partial class FrmClient : UIForm
    {
        // 客户端Socket对象，用于与服务器通信
        private Socket clientSocket;
        // 服务器IP地址
        private string serverIP;
        // 服务器端口号
        private int serverPort;
        // 标记客户端是否已连接
        private bool isConnected = false;
        // 用于尝试重新连接的定时器
        private System.Timers.Timer reconnectTimer;
        // 重连尝试次数
        private int reconnectAttempts = 0;
        // 最大重连尝试次数
        private int maxReconnectAttempts = 15; //15次，15秒可重联，超过重新创建对象
        // 重连间隔时间（毫秒）
        private int reconnectInterval = 1000;

        public FrmClient()
        {
            InitializeComponent();
            // 初始化定时器，用于断线重连
            reconnectTimer = new System.Timers.Timer(reconnectInterval);
            reconnectTimer.Elapsed += ReconnectTimer_Elapsed;
            reconnectTimer.AutoReset = false; //定时器不重复执行，只执行一次
        }



        private void btnStart_Click(object sender, EventArgs e)
        {
            //客户端连接服务器端
            LinkServer();
        }

        /// <summary>
        /// 连接服务器
        /// </summary>
        private void LinkServer()
        {
            try
            {
                // 获取服务器IP地址和端口号（假设在界面上已输入，这里简化获取方式）
                serverIP = txtIP.Text;
                serverPort = int.Parse(txtPort.Text);
                // 创建客户端Socket，使用IPv4、流式套接字、TCP协议
                clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                // 连接服务器
                clientSocket.Connect(new IPEndPoint(IPAddress.Parse(serverIP), serverPort));
                isConnected = true;
                AppendTextToTxtLog($"{DateTime.Now.ToString("HH:mm:ss")}:已成功连接服务器");
                // 在单独线程中启动接收服务器数据的方法，避免阻塞UI线程
                Thread receiveThread = new Thread(ReceiveData);
                receiveThread.Start();
                //发送心跳包子线程
                Thread heartThread = new Thread(sendHeartBeat);
                heartThread.IsBackground = true;
                heartThread.Start();
            }
            catch (SocketException ex)
            {
                AppendTextToTxtLog($"{DateTime.Now.ToString("HH:mm:ss")}:连接服务器失败：{ex.Message}");
            }
        }

        /// <summary>
        /// 发送心跳包
        /// </summary>
        private void sendHeartBeat()
        {
            while (true)
            {
                Thread.Sleep(10000); //10秒发送一次心跳
                string message = "heart";
                byte[] buffer = Encoding.UTF8.GetBytes(message);
                try
                {
                    // 向服务器发送消息
                    clientSocket.Send(buffer);
                    Console.WriteLine($"发送心跳包：{message}");
                }
                catch (SocketException ex)
                {
                    Console.WriteLine($"发送心跳包出错：{ex.Message}");
                }
            }
        }

        private void btnSendMsg_Click(object sender, EventArgs e)
        {
            if (clientSocket.Connected && isConnected)
            {
                byte[] data = Encoding.UTF8.GetBytes(txtMsg.Text);
                clientSocket.Send(data,0,data.Length,SocketFlags.None);
                AppendTextToTxtLog($"{DateTime.Now.ToString("HH:mm:ss")}发送: {txtMsg.Text}");
            }
        }


        //往日志文本框上添加数据
        public void AppendTextToTxtLog(string txt)
        {
            if (txtLog.InvokeRequired) //判断是否跨线程访问
            {
                //Invoke同步方法      BeginInvoke异步方法
                txtLog.Invoke(new Action<string>(s =>
                {
                    this.txtLog.Text = string.Format("{0}\r\n{1}", s, txtLog.Text);
                }), txt);
            }
            else //本线程内访问
            {
                this.txtLog.Text = string.Format("{0}\r\n{1}", txt, txtLog.Text);
            }
        }


        public void ReceiveData(object socket)
        {
            byte[] buffer = new byte[1024 * 1024];
            //byte[] data = new byte[500 * 1024 * 1024];
            //var proxySocket = socket as Socket;
            while (isConnected)
            {
                //int len = 0;

                //try
                //{
                //    len = proxySocket.Receive(data, 0, data.Length, SocketFlags.None);
                //}
                //catch (Exception ex)
                //{
                //    try
                //    {
                //        //服务器异常退出
                //        AppendTextToTxtLog(string.Format("服务器端：{0}非正常退出", proxySocket.RemoteEndPoint.ToString()));
                //    }
                //    catch { }
                //    stopConnect();  //停止连接
                //    return; //让方法结束，结束当前接收数据的异步线程
                //}

                //接收到0个字节代表客户端正常退出
                //if (len <= 0)
                //{
                //    //服务器正常退出
                //    AppendTextToTxtLog(string.Format("服务器端：{0}正常退出", proxySocket.RemoteEndPoint.ToString()));
                //    stopConnect();  //停止连接
                //    return; //让方法结束，结束当前接收数据的异步线程
                //}

                //if (data[0] == 1)
                //{  //接收字符串
                //    string str = Encoding.UTF8.GetString(data, 1, len - 1);
                //    //把接收到的数据放到文本框上
                //    AppendTextToTxtLog(string.Format("接收到服务器端：{0}的消息：{1}", proxySocket.RemoteEndPoint.ToString(), str));
                //}
                //else if (data[0] == 2)
                //{
                //    shake();
                //}
                //else if (data[0] == 3) 
                //{
                //    processReceiveFile(data,len);
                //}

                try
                {
                    // 接收服务器发送的数据，返回接收的字节数
                    int bytesReceived = clientSocket.Receive(buffer, 0, buffer.Length, SocketFlags.None);
                    if (bytesReceived == 0)
                    {
                        // 如果接收字节数为0，通常意味着服务器断开连接或网络异常
                        isConnected = false;
                        clientSocket.Close();
                        AppendTextToTxtLog($"{DateTime.Now.ToString("HH:mm:ss")}: 与服务器的连接已断开");
                        // 启动定时器，尝试重新连接
                        reconnectTimer.Start();
                        break;
                    }

                    //正常接收到数据，执行业务逻辑
                    try
                    {
                        if (buffer[0] == 1)
                        {  //接收字符串
                            string str = Encoding.UTF8.GetString(buffer, 1, bytesReceived - 1);
                            str = str.TrimEnd('\0');
                            //把接收到的数据放到文本框上
                            AppendTextToTxtLog($"{DateTime.Now.ToString("HH:mm:ss")} {clientSocket.RemoteEndPoint.ToString()}: {str}");
                        }
                        else if (buffer[0] == 2)
                        {
                            shake();
                        }
                        else if (buffer[0] == 3)
                        {
                            processReceiveFile(buffer, bytesReceived);
                        }
                    }
                    catch (Exception ex)
                    {

                    }
                }
                catch (SocketException ex)
                {
                    isConnected = false;
                    clientSocket.Close();
                    AppendTextToTxtLog($"{DateTime.Now.ToString("HH:mm:ss")}: 接收服务器数据时出错：{ex.Message}");
                    // 启动定时器，尝试重新连接
                    reconnectTimer.Start();
                    break;
                }
            }
        }

        private void processReceiveFile(byte[] data,int len)
        {
            this.Invoke(new Action(() => {
                using (SaveFileDialog sfd = new SaveFileDialog())
                {
                    byte[] nameData = new byte[64];
                    byte[] fileData = new byte[len - 1 - 64];
                    Buffer.BlockCopy(data, 1, nameData, 0, 64);
                    Buffer.BlockCopy(data, 1 + 64, fileData, 0, len - 1 - 64);
                    string filename = Encoding.UTF8.GetString(nameData);
                    sfd.FileName = filename;
                    sfd.DefaultExt = "txt";
                    sfd.Filter = "文本文件|*.txt|JPG|*.jpg|Doc|*.doc|所有文件|*.*";
                    if (sfd.ShowDialog(this) != DialogResult.OK)
                    {
                        return;
                    }
                    File.WriteAllBytes(sfd.FileName, fileData);
                }
            }));
        }

        private void shake()
        {
            //记录窗体原始坐标
            Point oldLocation = this.Location;
            Random rand = new Random();
            this.Invoke(new Action(() => {
                for (int i = 0; i < 50; i++)
                {
                    this.Location = new Point(
                        rand.Next(oldLocation.X - 5, oldLocation.X + 5),
                        rand.Next(oldLocation.Y - 5, oldLocation.Y + 5));
                    Thread.Sleep(5);
                    this.Location = oldLocation;
                }
            }));
        }

        private void stopConnect()
        {
            try
            {
                if (clientSocket.Connected)
                {
                    clientSocket.Shutdown(SocketShutdown.Both);
                    clientSocket.Close(100);

                }
            }
            catch (Exception ex) { 
                
            }
        }

        private string getIP()
        {
            //获取本机IP
            var hostName = Dns.GetHostName();
            var ipHost = Dns.GetHostEntry(hostName);
            var ipAddress = ipHost.AddressList.FirstOrDefault(ip => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork);
            if (ipAddress != null)
            {
                var ipv4Address = ipAddress.ToString();
                Console.WriteLine("IPv4 Address: " + ipv4Address);
                return ipv4Address;
            }
            else
            {
                return null;
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            txtIP.Text = getIP();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            //判断是否已连接,如果已连接就关闭连接
            stopConnect();

        }

        // 定时器触发事件处理方法，用于尝试重新连接服务器
        private void ReconnectTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            reconnectAttempts++;
            try
            {
                if (reconnectAttempts <= maxReconnectAttempts)
                {
                    // 关闭原客户端Socket
                    clientSocket.Close();
                    // 重新创建Socket对象尝试连接服务器（这里简化了一些配置，实际可能需要更多信息）
                    clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    clientSocket.Connect(new IPEndPoint(IPAddress.Parse(serverIP), serverPort));
                    isConnected = true;
                    //Console.WriteLine($"重新连接服务器成功，第{reconnectAttempts}次尝试");
                    reconnectAttempts = 0;
                    // 在单独线程中启动接收服务器数据的方法，避免阻塞UI线程
                    Thread receiveThread = new Thread(ReceiveData);
                    receiveThread.Start();
                }
                else
                {
                    //Console.WriteLine($"多次尝试重新连接服务器失败，放弃重连");
                }
            }
            catch (SocketException ex)
            {
                //Console.WriteLine($"第{reconnectAttempts}次重新连接服务器失败：{ex.Message}");
                // 再次启动定时器，进行下一次尝试
                reconnectTimer.Start();
            }
        }
    }
}
